#ifndef __IMPLS_H__
#define __IMPLS_H__
#include "definiciones.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// #include "arbol.h" para que mostrar arbol ande comente la estructura de arbol de arbol.h
// y pegue las implementaciones del .c 


///  comprimir_archivo  ///
int comprimir_archivo (const char *nomb_arch_entrada,	const char *nomb_arch_salida )
{
		//Abro el archivo en modo lectura
		FILE *ptr_archivo = fopen( nomb_arch_entrada, "r" );
		
		//Apunto el puntero del archivo al FINAL
		fseek (ptr_archivo, 0, SEEK_END);
    
    //FTELL devuelve la posicion en la que esta parado el puntero del archivo.
    //La posicion es el numero de bytes desde el principio hasta donde estoy parado
    //como estoy parado en el ultimo byte, devuelve final - principio == tamanio archivo =D
		unsigned int tamanio_arch_entrada = ftell (ptr_archivo);  
		
		//reservo esa cantidad de memoria para hacer el buffer
		unsigned char* ptr_buffer = (unsigned char*)malloc(tamanio_arch_entrada+1);

		//Todo esto se define en la funcion comprimir_buffer
		unsigned char *p_ptr_dst_buf = NULL;
		unsigned int ptr_dst_size= 0;
		codigo_t *p_ptr_tabla_codigos = NULL;
		unsigned int ptr_long_codificacion= 0;
		
		//Devuelvo el puntero de archivo al principio para empezar a copiar todo al buffer
		rewind(ptr_archivo);
		
		//Esto automaticamente lee todo y me lo guarda en el buffer (L)
		fread (ptr_buffer,sizeof(char),tamanio_arch_entrada,ptr_archivo);

		//Tecnicamente no necesito mas este archivo abierto
		fclose(ptr_archivo);


		if ( !comprimir_buffer( ptr_buffer, tamanio_arch_entrada, &p_ptr_dst_buf, &ptr_dst_size, &p_ptr_tabla_codigos, &ptr_long_codificacion )  )
		{
				printf("No se pudo comprimir!\n");
				// ojo, 0 es el codigo de error! Tengo q devolver algo > 0
				return 1;
		}

		
		//No necesito mas este buffer, lo libero
		free(ptr_buffer);
		
		//Armo todo para escribir el archivo comprimido
		
		//A partir de la tabla de codigos, tengo que crear una lista
		//de codificacion_t
		int cantidad_codigos = 0;
		codigo_t codigo_temp;
		//principio de la tabla
		codigo_t* tabla_codigos= p_ptr_tabla_codigos;
		int i;
		
		for(i = 0; i < 256; i++ )
		{
			codigo_temp = tabla_codigos[i];
			if(codigo_temp.valido == 1)
				cantidad_codigos++;
		}
		
		codificacion_t* lista_codificaciones =  (codificacion_t*) malloc( cantidad_codigos * sizeof(codificacion_t) );
		
		//principio de la tabla
		tabla_codigos= p_ptr_tabla_codigos;
		int j=0;
		for(i = 0; i < 256; i++ )
		{
				
				codificacion_t codificacion_temp;
				codigo_temp = tabla_codigos[i];
				if ( codigo_temp.valido == 1 )
				{
					codificacion_temp.simbolo = i;
					codificacion_temp.codigo = codigo_temp.codigo;
					codificacion_temp.long_codigo = codigo_temp.long_codigo;
					lista_codificaciones[j++] = codificacion_temp;
					
				}
		}

		//Creo el archivo de salida con permisos de escritura
		FILE *ptr_salida = fopen( nomb_arch_salida, "w" );
		
		//Tengo que guardar primero el header, lo armo
		oc2_header_t header;
		header.tam_original = tamanio_arch_entrada;
		header.long_codificacion = ptr_long_codificacion;
		header.cant_codigos = cantidad_codigos;
  		header.offset_codificacion = sizeof(oc2_header_t) + cantidad_codigos *sizeof(codificacion_t);
		
		//Escribo el header
		fwrite(&header,sizeof(header),1,ptr_salida);
		
		//Ahora guardo la tabla de codigos
		fwrite(lista_codificaciones,sizeof(codificacion_t),header.cant_codigos,ptr_salida);

		//Y ahora los datos comprimidos
		fwrite(p_ptr_dst_buf,1,ptr_dst_size,ptr_salida);

		

		//Cierro el archivo de salida, libero memoria, etc
		fclose(ptr_salida);
		free(p_ptr_tabla_codigos);
		free(p_ptr_dst_buf);
		free(lista_codificaciones);
		//Listou =D
		
		// ojo, 0 es el codigo de error! Tengo q devolver algo > 0
		return 1; 
}





/// descomprimir_archivo ///
int descomprimir_archivo (const char *nomb_arch_entrada, const char *nomb_arch_salida )
{
	FILE *ptr_archivo = fopen( nomb_arch_entrada, "r" );
	fseek (ptr_archivo, 0, SEEK_END);
  unsigned int tamanio_arch_entrada = ftell (ptr_archivo);
  unsigned char* ptr_buffer     = (unsigned char*)calloc(tamanio_arch_entrada,1);
  //---printf("reserve memoria: buffer de archivo de entrada\n");

	rewind(ptr_archivo);

	//Esto automaticamente lee todo y me lo guarda en el buffer (L)
	fread (ptr_buffer,sizeof(char),tamanio_arch_entrada,ptr_archivo);

	fclose(ptr_archivo);

	unsigned int tamanio_buffer = *(unsigned int*)ptr_buffer;

	unsigned char* ptr_dst_buffer = (unsigned char*)calloc(tamanio_buffer,1);
	//----printf("reserve memoria: buffer de destino\n");
	unsigned int dst_size = tamanio_buffer;
	codigo_t *p_ptr_tabla_codigo = NULL;

	unsigned int cant_cod = ((unsigned int*)ptr_buffer)[2];
	unsigned int long_codificacion = ((unsigned int*)ptr_buffer)[1];


	cargar_tabla_codigo_desde_buffer( ptr_buffer , cant_cod, &p_ptr_tabla_codigo );
	
	//ptr_buffer: datos comprimidos dst:datos descomprimidos
  if( !descomprimir_buffer ( ptr_buffer, long_codificacion, ptr_dst_buffer,  dst_size, p_ptr_tabla_codigo ) )
		{
				printf("No se pudo descomprimir!");
				return 0;
		}
		
		
	FILE *ptr_salida = fopen( nomb_arch_salida, "w" );
	fwrite(ptr_dst_buffer,dst_size,1,ptr_salida);
	fclose(ptr_salida);

	free(ptr_buffer); //----printf("libere buffer de archivo de entrada\n");
	free(p_ptr_tabla_codigo);//----- printf("libere tabla codigo\n");
	free(ptr_dst_buffer); //-------printf("libere tabla codigo\n");
	
	return 1;
}



void alinear ( char ch, int n ) {
	int i;
 	for ( i = 0; i < n; i++ ) {
		putchar ( ch );
	}
}
 
void estructura ( nodo_arbol_t *raiz, int nivel ) {
	if ( raiz == NULL ) {
		alinear ( '\t', nivel );
		puts ( "~" );
	} else {
		estructura ( raiz->der, nivel + 1 );
		alinear ( '\t', nivel );
		//printf ( "%d\n", raiz->simbolo );
		estructura ( raiz->izq, nivel + 1 );
	}
}


void mostrarArbol(nodo_arbol_t *raiz) {
	estructura(raiz, 0);
	
}

 void borrar_arbol(nodo_arbol_t * a ){
	if (a != NULL){
		borrar_arbol(a->izq);
		borrar_arbol(a->der);
		free(a);
		//printf("Libere nodo arbol\n");
	}	
}


/// descomprimir_buffer ///
int descomprimir_buffer ( unsigned char *src_buf,	unsigned int long_codificacion, unsigned char *dst_buf,	unsigned int dst_size, codigo_t *tabla_codigos )
{
		nodo_arbol_t *ptr_ptr_nodo_arbol  = NULL;
		
		if( !cargar_arbol_huffman( tabla_codigos,  &ptr_ptr_nodo_arbol ) )
		{
			printf("No se pudo cargar los datos de descompresion!");
			return 0;
		}

		unsigned int offset = ((oc2_header_t*)src_buf)->offset_codificacion;
		src_buf = src_buf + offset;
		
		//recorro arbol, escribo buffer
		bit Bit;
		nodo_arbol_t *ptr_nodo_arbol = ptr_ptr_nodo_arbol;
		nodo_arbol_t *ptr_nodo_temp = ptr_nodo_arbol;
		unsigned char byte_del_buffer;
		int i,j;
		unsigned int cant_codificaciones;
		if (long_codificacion % 8 == 0)
			cant_codificaciones = long_codificacion/8;
		else
 			cant_codificaciones = long_codificacion/8 +1;
 		int porcentaje =0;
		for(i = 0; i<cant_codificaciones;i++)
		{
				//Hago 4 llamadas porq sino va tan rapido el programa q no alcanza a printear
				if ((cant_codificaciones/100) != 0 && i % (cant_codificaciones/100) == 0){
					printf("\r%d%% descomprimido.", porcentaje );
					printf("\r%d%% descomprimido.", porcentaje );
					printf("\r%d%% descomprimido.", porcentaje );
					printf("\r%d%% descomprimido.", porcentaje++ );
				}
				byte_del_buffer = src_buf[i];
				//------printf("%x ",byte_del_buffer);
				//necesito el reverso de este char, en asm se hace facil con rotates
				unsigned char rev = 0;
				int k;
				for ( k = 0; k < 8; k++)
				{
				rev *= 2; //shift 1 bit a izq
					rev = rev + (byte_del_buffer % 2);
					byte_del_buffer = byte_del_buffer / 2;
					
				}
				byte_del_buffer = rev;
				//------printf("%x\n",byte_del_buffer);
				
				for(j=0;j<8;j++)
				{
					Bit.b = byte_del_buffer;
					if(Bit.b)
					{
							//Leo un 1
							if(((nodo_arbol_t*)ptr_nodo_temp->izq)->izq)
							{
								ptr_nodo_temp = ptr_nodo_temp->izq;
							}
							else
							{
								*dst_buf = ((nodo_arbol_t*)ptr_nodo_temp->izq)->simbolo;
								dst_buf++;
								ptr_nodo_temp = ptr_nodo_arbol;
							}
					}
					else
					{
						//Leo un 1
						if(((nodo_arbol_t*)ptr_nodo_temp->der)->der)
						{
							ptr_nodo_temp = ptr_nodo_temp->der;
							//~byte_del_buffer = byte_del_buffer >> 1;
						}
						else
						{
							*dst_buf = ((nodo_arbol_t*)ptr_nodo_temp->der)->simbolo;
							dst_buf++;
							ptr_nodo_temp = ptr_nodo_arbol;
					}
				}
								byte_del_buffer = byte_del_buffer >> 1;

			}
	  }
		
		borrar_arbol(ptr_ptr_nodo_arbol);
		printf("\n");
		return 1;
}





/// comprimir_buffer ///
int comprimir_buffer ( unsigned char *scr_buf, unsigned int scr_size,	unsigned char **dst_buf, unsigned int *ptr_dst_size,
											codigo_t **tabla_codigos, unsigned int *long_codificacion )
{
	
		//Genero la tabla de apariciones
		unsigned int *ptr_tabla_apariciones = generar_tabla_apariciones( scr_buf, scr_size );
			
		//Genero la tabla de codigos
		codigo_t *ptr_tabla_codigos = generar_tabla_codigos(ptr_tabla_apariciones);

		//Caluclo la longitud
		*long_codificacion = calcular_longitud_codificacion( ptr_tabla_apariciones, ptr_tabla_codigos );
	
		unsigned int cant_codificaciones;
		if ((*long_codificacion) % 8 == 0)
			cant_codificaciones = (*long_codificacion)/8;
		else
 			cant_codificaciones = (*long_codificacion)/8 +1;

		unsigned int dst_size = sizeof(oc2_header_t)+(*long_codificacion)+cant_codificaciones;
		*dst_buf = calloc(dst_size,sizeof(char));
		if(!*dst_buf)
		{
				printf("No se pudo reservar memoria!\n");
				return 0;
		}
		//Genero la codificacion, sino se pudo, error
		if( !generar_codificacion( scr_buf, scr_size, *dst_buf, dst_size, ptr_tabla_codigos ) )
		{
				printf("No se pudo codificar!\n");
				return 0;
		}
		
		*ptr_dst_size=cant_codificaciones;
		*tabla_codigos = ptr_tabla_codigos;
		//Libero la tabla de apariciones
		free(ptr_tabla_apariciones);

		// ojo, 0 es el codigo de error! Tengo q devolver algo > 0
		return 1;
}

/// generar_tabla_apariciones ///
unsigned int *generar_tabla_apariciones ( unsigned char *buf,unsigned int size )
{
	
	//Recorro byte por byte y aumento la cantidad i
	
	//Uso CALLOC asi me inicializa todo a cero automaticamente
	unsigned int* tabla = (unsigned int*) calloc(256,sizeof(unsigned int));
	//~if(!tabla) printf("!·WEQDSACXZ");

	int i;
	for(i=0;i<size;i++)
		//ojala funcione esto..(lo del [])
		tabla[buf[i]]++;


	return tabla;
	
}



/// generar_tabla_codigos ///
codigo_t *generar_tabla_codigos ( unsigned int *tabla_apariciones )
{
  	 
	
	//saco el tamanio de la tabla de codigos
	int i;
	int tamanio_res = 0;
	for(i=0;i<256;i++)
		if(tabla_apariciones[i] > 0)
			tamanio_res++;
	

	

	codigo_t *res= (codigo_t*)calloc(256,sizeof(codigo_t));
	nodo_lista_t *ptr_nodo_lista = NULL; //(nodo_lista_t *) calloc(tamanio_res,sizeof(nodo_lista_t));
	nodo_lista_t **lista = &ptr_nodo_lista;
	
	nodo_arbol_t *tabla_arboles[256];
	
	
	
	crear_lista_huffman (tabla_apariciones,lista, tabla_arboles);

	nodo_arbol_t *ptr_raiz_arbol = NULL;
	nodo_arbol_t ** arbol_huff = &ptr_raiz_arbol;

	crear_arbol_huffman ( lista, arbol_huff );


	codigo_t *temp_res = res;

	for(i=0;i<256;i++)
	{
		if(tabla_arboles[i] != NULL)
		{
			int codigo_error;
			codigo_error = generar_codigo( *arbol_huff, tabla_arboles[i] , temp_res);	
			if (codigo_error == 0){
				printf("Error al comprimir: el codigo supera los 32 bits.");
//				break;

			}
		}
			temp_res++;			
	}

	borrar_arbol(*arbol_huff);
	
	return res;
}





/// generar_codificacion ///
int generar_codificacion ( unsigned char *src_buf, unsigned int src_size,
		unsigned char *dst_buf, unsigned int dst_size, codigo_t *tabla_codigos )
{

	unsigned char byte_a_escribir = 0;
	int bits_agregados = 0;
	int porcentaje = 0;
	
	int i,j;
	for( i = 0; i<src_size; i++)
	{
	
		if ((src_size/100) != 0 && i % (src_size/100) == 0)
		{
			//Hago 4 llamadas porq sino va tan rapido el programa q no alcanza a printear
			printf("\r%d%% comprimido.", ( porcentaje));
			printf("\r%d%% comprimido.", ( porcentaje));
			printf("\r%d%% comprimido.", ( porcentaje));
			printf("\r%d%% comprimido.", ( porcentaje++));
		}
			
		unsigned char byte_src = src_buf[i];
		codigo_t temp = tabla_codigos[byte_src];
		if( temp.valido != 1)
		{
				printf("Hay un error con la tabla!\n");
				return 0;
		}

		unsigned int reverso = temp.codigo_rev;
		for( j = 0; j<temp.long_codigo; j++)
		{
			int a = reverso % 2;
			if ( bits_agregados == 7)
			{
				byte_a_escribir = byte_a_escribir << 1;
				byte_a_escribir += a;
				*dst_buf = byte_a_escribir;
				dst_buf++;
				bits_agregados = 0;
				byte_a_escribir = 0;
			}
			else
			{
				byte_a_escribir = byte_a_escribir << 1;
				byte_a_escribir += a;
				bits_agregados++;
			}
			reverso = reverso >> 1;
		}
		
	}
	if (bits_agregados != 7)
	{
		bits_agregados--; //No estoy seguro porq, pero lo necesito..
		
		while(bits_agregados++ != 7)
				byte_a_escribir = byte_a_escribir << 1;

		*dst_buf = byte_a_escribir;
	}
	printf("\n");
	return 1;
}





/// calcular_longitud_codificacion ///
int calcular_longitud_codificacion ( unsigned int *tabla_apariciones,	codigo_t *tabla_codigo )
{
	//recorro la tabla_apariciones, si lo q hay es != 0 entonces entro a tabla_codigo y sumo la longitud
	int res=0;	
	int i;
	for(i=0;i<256;i++)
		if(	tabla_apariciones[i] )
			res += tabla_codigo[i].long_codigo*tabla_apariciones[i];
	
	return res;
}

/// lista_insertar_ordenado ///
void lista_insertar_ordenado( nodo_lista_t **l, nodo_lista_t *n)
{
	nodo_lista_t* lista = *l;
	if(*l==NULL){
		*l = n;
	}
	if(lista == NULL)
	{
		*l = n;
		return;
	}
	if( lista->nodo_arbol == NULL )
	{
		lista->nodo_arbol = n->nodo_arbol;
		lista->sig = n->sig;
	}
	else
	{
		unsigned int apariciones = n->nodo_arbol->apariciones;
		//menor al primero de la lista
		if( apariciones < lista->nodo_arbol->apariciones)
		{
			nodo_arbol_t* tempnodo= lista->nodo_arbol;
			nodo_lista_t* tempdir= lista->sig;
			lista->nodo_arbol = n->nodo_arbol;
			lista->sig = n;
			n->nodo_arbol = tempnodo;
			n->sig = tempdir;
		}
		else
		{
			while( lista->sig != NULL && ((nodo_lista_t*)lista->sig)->nodo_arbol->apariciones <= apariciones )
				lista = lista->sig;

			n->sig = lista->sig;
			lista->sig = n;
			
		}
	}

}





/// crear_arbol_huffman ///
void crear_arbol_huffman ( nodo_lista_t **l, nodo_arbol_t **a )
{
	//asumo que la lista no es vacía
	// a es el puntero al puntero a nodoarbol
	// ____ *a es el puntero al nodo arbol (mas precisamente a su raiz)
	// _________ **a es la raiz del arbol
	
	nodo_lista_t* primero_en_apariciones= NULL; //*primero... es puntero al nodo_arbol (con menos apariciones)
	nodo_lista_t* segundo_en_apariciones= NULL; //*segundo... es puntero al nodo_arbol (con menos apariciones')
	//C no tiene incluido el tipo bool
	int creado = 0;
	while (creado != 1) {
		lista_obtener_primero(l, &primero_en_apariciones);
		//si había un sólo elemento (la lista quedó vacía);
		if (*l == NULL){
			*a = (primero_en_apariciones)->nodo_arbol; //a es el puntero al nodo arbol, del nodo que extraje
			free(primero_en_apariciones);
			creado = 1;
		}
		//si había mas de uno
		else {
			lista_obtener_primero(l, &segundo_en_apariciones);
			nodo_arbol_t* ptr_nueva_raiz = (nodo_arbol_t *) malloc(sizeof(nodo_arbol_t));
			ptr_nueva_raiz->padre = NULL;
			// lo enlazo a sus nuevos hijos
			ptr_nueva_raiz->izq = primero_en_apariciones->nodo_arbol;
			ptr_nueva_raiz->der = segundo_en_apariciones->nodo_arbol;
		
			//libero memoria
			free(primero_en_apariciones);
			free(segundo_en_apariciones);
		
			// enlazo a los hijos con el padre
			((nodo_arbol_t*)ptr_nueva_raiz->izq)->padre = ptr_nueva_raiz;
			((nodo_arbol_t*)ptr_nueva_raiz->der)->padre = ptr_nueva_raiz;
			// defino las apariciones del padre como la suma de la de sus hijos
			ptr_nueva_raiz->apariciones = ((nodo_arbol_t*)ptr_nueva_raiz->izq)->apariciones + ((nodo_arbol_t*) ptr_nueva_raiz->der)->apariciones;
			// no es valido porque no es una hoja
			ptr_nueva_raiz->valido = 0;
		
			nodo_lista_t* ptr_nuevo_nodo_lst = (nodo_lista_t *) malloc(sizeof(nodo_lista_t));
			ptr_nuevo_nodo_lst->nodo_arbol = ptr_nueva_raiz;
			ptr_nuevo_nodo_lst->sig = NULL; //por si acaso
			
			
			lista_insertar_ordenado(l, ptr_nuevo_nodo_lst);
			
		}
	}
			
}



/// lista_obtener_primero ///
void lista_obtener_primero ( nodo_lista_t **l, nodo_lista_t **n )
{
	nodo_lista_t* ptr_primero = *l;
	nodo_lista_t* res = ptr_primero;
	res->nodo_arbol = ptr_primero->nodo_arbol;
	res->sig = ptr_primero->sig;
	*n=res;
	*l = ptr_primero->sig;
	//deberia liberar memoria de l[0]...
}






/// crear_lista_huffman ///
void crear_lista_huffman ( unsigned int *tabla_apariciones,	nodo_lista_t **l, nodo_arbol_t **indices_nodos_simbolos ){
	
	
	
	//unsigned int *tabla_apariciones   array dee apariciones
	// nodo_lista_t **t puntero a puntero al primero de la lista
	//nodo_arbol_t ** indices_nodos_simbolos  es el puntero a puntero de la hoja encuestion
	// agregar ordenado--------void lista_insertaro_ordenado(nodo_lista_t **l, nodo_lista_t *a)

	int i=0;
	while(i<256){
		
		if(tabla_apariciones[i]>0){
			//printf("en listaH, simbolo\n");
			//printf("%c \n",i);
			//printf("aparece:   ");
			//printf("%d \n",tabla_apariciones[i] );
			nodo_lista_t* nuevo_nodo = (nodo_lista_t*)malloc(sizeof(nodo_lista_t)); 	
			unsigned char simbolo = (unsigned char) i;	//si ese simbolo aparece, lo casteo a char
			nodo_arbol_t* hoja = (nodo_arbol_t*)malloc(sizeof(nodo_arbol_t)); //me creo un nodo de arbol
			hoja->simbolo = simbolo;		//le pongo el simbolo correspondiente
			hoja->apariciones = tabla_apariciones[i];		//le pongo cuantas veces aparece
			hoja->valido = 1;					//por ahora es valido...
			(hoja->izq) = NULL;					//seteo padres e hijos en null
			(hoja->der) = NULL;
			(hoja->padre) = NULL;
			nuevo_nodo->nodo_arbol = hoja;
			nuevo_nodo->sig = NULL;
			indices_nodos_simbolos[i]=hoja;	//hago que el arreglo [sub ese char] apunte a ese nodo
			lista_insertar_ordenado(l,nuevo_nodo);	//inserto ese nodo ordenadamente en la lista
		}else {
			indices_nodos_simbolos[i]=NULL;		//si ese simbolo nunca aparecio, solo pongo null
		}
		i=i+1;
	}

}





/// generar_codigo ///
int generar_codigo ( nodo_arbol_t *a, nodo_arbol_t *h, codigo_t *c )	{
	//mostrarArbol(a);

	//printf("entre a generar codigo\n");

	if( a== NULL){
		c->valido=0; //hace falta que meta 0 aca?? diciendo que el codigo no es valido??
	//	printf("entre al if\n");
		return 0;//el arbol es vacio
	}
//	unsigned int* codigo =(unsigned int*)malloc(32*sizeof(unsigned int));//me hago un arreglo de uint para guardar el "camino" de h a la raiz
	unsigned int codigo[32];
	int j=0;
	while(j<32){
		codigo[j]=0;       //seteo el array en 0
		j=j+1;
	}
	nodo_arbol_t*  iter = h;	//me hago un puntero a nodo iter apuntando a *h, que voy a usar para recorrer el arbol
	int tam=0;			//tam es el contador, y cuando termine el ciclo me va a decir el tamaño del codigo
	//printf("se viene el simobloooo\n");
	//printf("%c \n",h->simbolo);
	//printf("ahora se viene el codigo pero en bits, de atras para adelante\n");
	while(tam<32){			//si llego a 32 dejo de recorrer y devuelvo error
		if(iter->padre==NULL){	//llegue a la raiz, salto del while. Si es mas declarativo, se mete en la guarda del while con un and
			break;
		}
		if(iter == ((nodo_arbol_t*)(iter->padre))->izq){	//si es hijo izq entonces corresponde 0
			codigo[tam]=0;

		} else {
			codigo[tam]=1; //si es hijo der entonces corresponde 1
		}
		//printf("%d \n",codigo[tam]);
		tam = tam+1;
		iter=iter->padre;
		//h = h->padre;
	}
	if(tam == 32){	//quiere decir que la codificaion llego a 33bits y devuelvo error
		c->valido = 0;
		return 0;
	}
	//HAGO ESTA TERRIBLE SARASEADA PORQUE NO SE SHIFTEAR EN C
	int i=0;
	unsigned int codigo_derecho=0;
	unsigned int codigo_reves=0;
	while(i<tam){
	// recorro el arreglo de 0's y 1's, y en la primera posicion lo pongo. le hago un and con el 2do shifteado una vez, osea, lo pongo en el 2do bit.
	//luego un and con el 3ro shifteado 2 veces, osea, le agrego el 3er bit, y asi sucesivamente. Me queda el codido en un uin y en tam el tamaño en bits del codiogo
		//codigo_reves =codigo[i] + (codigo_reves*2^(i)); 
		//codigo_derecho = codigo[tam-i] + (codigo_derecho*2^(i)); 
		//i=i+1;
		codigo_reves = (codigo_reves*2)+codigo[i];
		codigo_derecho = (codigo_derecho*2)+codigo[tam-i-1];
		i = i+1;
	}
	//printf("%d \n", tam);
	c->codigo = codigo_derecho;		//guardo lo que hice en el codigo que tengo que devolver
	//printf("se viene el codigo derechooo\n");
	//printf("%d \n",codigo_derecho);
	c->codigo_rev = codigo_reves;
	//printf("se viene el codigo reversooo\n");
	//printf("%d \n",codigo_reves);
	c->long_codigo = tam;
	c->valido = 1;
	//free(codigo); //libero la memoria del array que me hice
	return 1; 		//devuelvo 1 que es distinto al 0 que es el cogido de error

}



/// cargar_tabla_codigo_desde_buffer///
int cargar_tabla_codigo_desde_buffer ( unsigned char * buf,unsigned int size, codigo_t **tabla_codigo ){

	int tabla_size = 256;
	codigo_t * ptr_tabla_codigo = (codigo_t *)calloc(tabla_size, sizeof(codigo_t));
	//~printf("reserve memoria: tabla codigo\n");
	
	// si no pudo reservar memoria, devuelve error
	if (ptr_tabla_codigo == NULL)
		return 0;

	*tabla_codigo = ptr_tabla_codigo;	

		
	int i;
	buf = buf+sizeof(oc2_header_t);
	codificacion_t * ptr_buf = (codificacion_t*) buf;
	
	for (i = 0; i < size; i++){
		unsigned char simbolo_buf = ptr_buf->simbolo;
		unsigned int codigo_buf = ptr_buf->codigo;
		unsigned int longcodigo_buf = ptr_buf->long_codigo;
		
		(ptr_tabla_codigo[simbolo_buf]).codigo = codigo_buf;

		
		int k;
		unsigned int codigo_buf_rev = 0;
		//creo el reverso, vi que trabajaste con bits, pero a mi me gusta complicármela
		for ( k = 0; k < longcodigo_buf; k++){
			codigo_buf_rev *= 2; //shift 1 bit a izq
			//saco el ultimo bit de codigo y lo agrego desde la derecha a codigo_buf_rev
			codigo_buf_rev = codigo_buf_rev + (codigo_buf % 2);
			//shift 1 bit a der, a codigo
			codigo_buf = codigo_buf / 2;

		}
			(ptr_tabla_codigo[simbolo_buf]).codigo_rev = codigo_buf_rev;
	
		(ptr_tabla_codigo[simbolo_buf]).long_codigo = longcodigo_buf;

		(ptr_tabla_codigo[simbolo_buf]).valido = 1;
		
		ptr_buf++;
	}
	
	//las otras posiciones tienen ceros. Así que si accedo a valido, va a tener 0
	
	return 1;
}


/// cargar_arbol_huffman ///
int cargar_arbol_huffman(codigo_t *tabla_codigos, nodo_arbol_t **a ){
	//*tabla_codigos	es el puntero a la tabla de codigos
	//**a   es un puntero a un puntero a arbol
	int tam = 0;//tabla_codigos.max_size();		//esto debe ser 256, pero no estaba seguro
	nodo_arbol_t* raiz=(nodo_arbol_t*)malloc(sizeof(nodo_arbol_t));		//creo la raiz del arbol
	*a = raiz;		//ahora si es la raiz del arbol
	raiz->valido=0; //con esto quiero decir que no tiene ningun valor este nodo
	raiz->padre = NULL;
	raiz->izq = NULL;
	raiz->der = NULL;
	while(tam<256){	//recorro la tabla uno por uno
		if(tabla_codigos[tam].valido == 1){	//si el simbolo "i" aparece, entonces...
			int tam_camino=tabla_codigos[tam].long_codigo;		//me guardo la long del codigo de i
			unsigned int camino = tabla_codigos[tam].codigo_rev;		//me copio el camino para toquetearlo
			nodo_arbol_t* iter = raiz;				//creo un interador para recorrer el arbol
			while(tam_camino>0)
			{					//mientras tengo codigo
				int i=camino%2;				
				if(i==1){			//si el ultimo bit es 0...
					if(iter->izq == NULL){		//si no habia un nodo lo creo y sigo
						nodo_arbol_t* nuevo_nodo=(nodo_arbol_t*)malloc(sizeof(nodo_arbol_t));
						//printf("reserve memoria: nodo arbol\n");
						iter->izq = nuevo_nodo;
						nuevo_nodo->valido = 0;
						nuevo_nodo->padre = iter;
						nuevo_nodo->izq = NULL;
						nuevo_nodo->der = NULL;
						iter = iter->izq;
					} else {
						iter = iter->izq; //si ya habia un nodo apunto a ese y sigo recorriendo
					}
				} else {
					if(iter->der == NULL){ // idem pero si el ultimo biy es 1...
						nodo_arbol_t* nuevo_nodo=(nodo_arbol_t*)malloc(sizeof(nodo_arbol_t));
						//printf("reserve memoria: nodo arbol\n");
						iter->der = nuevo_nodo;
						nuevo_nodo->valido = 0;
						nuevo_nodo->padre = iter;
						nuevo_nodo->izq = NULL;
						nuevo_nodo->der = NULL;
						iter = iter->der;
					} else {
						iter = iter->der;
					}
				}
			tam_camino = tam_camino - 1; //resto uno a la longitud
			camino = camino/2; //shifteo o divido por 2 para ver el proximo bit
			}
		iter->simbolo =(unsigned char)tam;  //casteo el entero a char y pongo el simbolo en el arbol
		iter->valido = 1;	//digo que este nodo SI tiene un valor valido

		}
	tam++; 	//inc  i y sigo con el proximo simbolo de la tabla
	}

	 return 1;
}


#endif
